<HTML>
<HEAD>
<TITLE>JavaScript Source Code 3000:  Games:  Maze</TITLE>
<META HTTP-EQUIV="JavaScript Source Code 3000" CONTENT = "no-cache">
<META NAME="date" CONTENT="2000-09-09">
<META NAME="channel" CONTENT="Web Developer">
<META NAME="author" CONTENT="Jason Hotchkiss (jasonhotchkiss@home.com)">
<META NAME="section" CONTENT="Games">
<META NAME="description" CONTENT="Navigate around a 3D JavaScript maze in search of the exit in the fewest moves possible.  The maze is complex, but you can cheat by taking a peak at the map.  Tested in IE5 and Netscape.">
</HEAD>

<BODY BGCOLOR=#ffffff vlink=#0000ff>

<BR>
<center>
<table width=600 cellpadding=0 cellspacing=10>
<tr>
<td width=468 align=center>

    
    
</td>
<td width=120 align=center>
    
</td>
</tr>
</table>
<BR>
<BR>
<basefont size=3>
<FONT SIZE="+2" FACE="Helvetica,Arial">
<A HREF="../index.htm" /" TARGET="_top"><FONT COLOR="#0000FF"><b>Home</b></font></A>
<img src="../img/arrow.gif" /img/arrow.gif" height=13 width=7 border=0 alt="}">
<A HREF="index.htm" /games/"><font color="#FF0000"><b>Games</b></font></A>
<img src="../img/arrow.gif" /img/arrow.gif" height=13 width=7 border=0 alt="}">
<FONT COLOR="#006666"><b>Maze</b></font></font>
<BR>
<BR>
<table BORDER=0 WIDTH=486 CELLPADDING=3 CELLSPACING=0>
<tr><td><font FACE="helvetica,arial,geneva">
<br>
<br>
<!-- Description --><!--content_start-->
Navigate around a 3D JavaScript maze in search of the exit in the fewest moves possible.  The maze is complex, but you can cheat by taking a peak at the map.  Tested in IE5 and Netscape.
<hr>
</td></tr>
</table>
<!-- Demonstration -->

<center>
<form name="openpage">
<input type=button value="Open Maze Game" onClick="window.open('maze-demo.html');">
</form>
</center>


<P>
<P>
<a name="source">
<table BORDER=0 WIDTH=486 CELLPADDING=3 CELLSPACING=0>
<tr><td BGCOLOR=yellow><font FACE="helvetica,arial,geneva"><b>JavaScript Source Code 3000:  Games:  Maze</b>
<p>Simply click inside the window below, use your cursor to highlight the script, and copy (type Control-c or Apple-c) the script into a new file in your text editor (such as Note Pad or Simple Text) and save (Control-s or Apple-s).  The script is yours!!!
<br><br></font></td></tr>
<tr><td BGCOLOR=yellow ALIGN=CENTER>
<form NAME="copy">

<DIV align="center">
<input type=button value="Highlight All" onClick="javascript:this.form.txt.focus();this.form.txt.select();">&nbsp;&nbsp;&nbsp;&nbsp;
<INPUT TYPE="text" NAME="total" VALUE="Script Size:  10.58 KB" size=24>
</DIV>

<textarea NAME="txt" ROWS=20 COLS=75 WRAP=VIRTUAL>

&lt;!-- THREE STEPS TO INSTALL MAZE:

  1.  Put the maze button in the opening HTML page
  2.  Include the next code into the HEAD of the maze page (maze.html)
  3.  Add the last code into the BODY of the maze page (maze.html) --&gt;

&lt;!-- STEP ONE: Put the button into the opening HTML page  --&gt;

&lt;center&gt;
&lt;form name="openpage"&gt;
&lt;input type=button value="Open Maze Game" onClick="window.open('maze.html');"&gt;
&lt;/form&gt;
&lt;/center&gt;

&lt;!-- STEP TWO: Add the next code into the HEAD of the maze page (maze.html)  --&gt;

&lt;HEAD&gt;

&lt;style type="text/css"&gt;
.viewport { background:white;text-align:center }
.readout { color:white;background:black;font-family:sans-serif;font-size:8pt;font-weight:bold;text-align:center }
&lt;/style&gt;
&lt;/HEAD&gt;

&lt;!-- STEP THREE: Copy this final code into the BODY of the maze page (maze.html)  --&gt;

&lt;BODY&gt;

&lt;center&gt;
&lt;layer name="viewport" top=10 height=340 bgcolor="white"&gt;
&lt;nolayer&gt;
&lt;div id="viewport" class="viewport" style="width:0;height:200"&gt;&lt;/div&gt;
&lt;/nolayer&gt;
&lt;/layer&gt;

&lt;layer name="readout" top=350 height=40&gt;
&lt;nolayer&gt;
&lt;div id="readout" class="readout"&gt;&lt;/div&gt;
&lt;/nolayer&gt;
&lt;/layer&gt;

&lt;layer top=380&gt;
&lt;form&gt;
&lt;input type=button onclick="javascript:turn(-1);" value="Left"&gt;
&lt;input type=button onclick="javascript:move();" value="Forward"&gt;
&lt;input type=button onclick="javascript:turn(1);" value="Right"&gt;&lt;br&gt;
&lt;input type=button onclick="javascript:cheat();" value="Cheat"&gt;
&lt;/form&gt;
&lt;/layer&gt;
&lt;/center&gt;


&lt;SCRIPT LANGUAGE="JavaScript"&gt;
&lt;!-- Original:  Jason Hotchkiss (jasonhotchkiss@home.com) --&gt;

&lt;! &gt;
&lt;! &gt;

&lt;!-- Begin
// The binary data for the maze
var map = [
[ 255, 255, 255, 255, 255, 255, 255, 255 ],
[ 162,   8,   3, 248,   0,   0,   0,  17 ],
[ 136, 162, 235, 251, 254, 237, 221, 213 ],
[ 187, 190,  10, 170, 162,  68, 136, 149 ],
[ 136, 130, 186, 170, 171,  86, 170, 181 ],
[ 238, 250, 130,   0,  10,  68, 136, 149 ],
[ 130, 130,  30, 255, 250, 238, 221, 213 ],
[ 186, 190, 248, 128,   2, 137,  17,  21 ],
[ 168,  32,   2,  42, 174, 187, 119, 117 ],
[ 139, 239, 235, 170, 226,  34,  68,  69 ],
[ 250,  40,  32, 170,  42, 190, 255, 213 ],
[ 130, 234, 182, 162, 170, 138,   0,  21 ],
[ 170, 136,  34,  62, 170,  34, 255, 253 ],
[ 168, 191, 168, 160, 131, 234, 162,  35 ],
[ 175, 160, 170, 175, 170,  14, 186, 233 ],
[ 168,  42,  42, 234, 170, 224, 130,  37 ],
[ 163, 171, 162,   0,  34,  63, 187, 181 ],
[ 190,  34,  63, 127, 254, 138, 160, 133 ],
[ 162, 234, 160,  16,  34,  40, 189,  85 ],
[ 138, 170, 175, 213, 226, 238, 165, 125 ],
[ 248, 162,  40,  84,  34,   8,   8,  37 ],
[ 130,  43, 171,  85, 163, 235, 251, 169 ],
[ 175, 234,  33,  20, 130,   9,   1,  15 ],
[ 160,  66, 173, 246, 174, 253, 125,  97 ],
[ 191,  94,  32, 162,  32,   5,  69,  45 ],
[ 162,  75, 234,  43, 238, 213,  21, 105 ],
[ 168, 106,  42, 238,   2,  17,  68,  37 ],
[ 175, 202, 130,   2, 171,  95,  95, 141 ],
[ 168, 154, 254, 190, 171, 113,  18, 213 ],
[ 130,   2,   0, 128,   2,   4,  70,   5 ],
[ 255, 255, 255, 255, 255, 255, 255, 255 ]
];

// The visible part of the map
var aspect = [];

// The character map of the viewport
var view = [];

var exitx=24,exity=57,xpos,ypos,dir,mapon,steps,cheats;

// Function to initialise the variables.
function start() {
xpos = 1;
ypos = 1;
dir=2;
steps=0;
cheats=0;
setTimeout("draw()",100);
}

// function to lookup contents of a position in the map
function getGrid(x,y) {
if( x&lt;0 || x&gt;30 || y&lt;0 || y&gt;63 )
return true;
if( ((map[x][Math.floor(y/8)]) & (128&gt;&gt;&gt;(y%8))) &gt; 0 )
return true;
return false;
}

// function to render a wall
function render( col, len, data ) {
var i;
for( i=0; i&lt;14; ++i )
view[i] = view[i].substr(0,col) + data[i] + view[i].substr(col+len,27-col-len);
}

// function to update the display
function draw() {
var atexit;
mapon = false;

// Fill the 'aspect' array with positions of visible walls
switch(dir) {
case 0: 
aspect = [  getGrid(xpos,ypos-1),getGrid(xpos,ypos+1),getGrid(xpos-1,ypos-1),
getGrid(xpos-1,ypos),getGrid(xpos-1,ypos+1),getGrid(xpos-2,ypos-1),
getGrid(xpos-2,ypos),getGrid(xpos-2,ypos+1),getGrid(xpos-3,ypos-1),
getGrid(xpos-3,ypos),getGrid(xpos-3,ypos+1),getGrid(xpos-4,ypos) ];
atexit = (xpos == exitx + 1 && ypos == exity );
break;
case 1:
aspect = [  getGrid(xpos-1,ypos),getGrid(xpos+1,ypos),getGrid(xpos-1,ypos+1),
getGrid(xpos,ypos+1),getGrid(xpos+1,ypos+1),getGrid(xpos-1,ypos+2),
getGrid(xpos,ypos+2),getGrid(xpos+1,ypos+2),getGrid(xpos-1,ypos+3),
getGrid(xpos,ypos+3),getGrid(xpos+1,ypos+3),getGrid(xpos,ypos+4) ];
atexit = (xpos == exitx && ypos == exity-1 );
break;
case 2:
aspect = [  getGrid(xpos,ypos+1),getGrid(xpos,ypos-1),getGrid(xpos+1,ypos+1),
getGrid(xpos+1,ypos),getGrid(xpos+1,ypos-1),getGrid(xpos+2,ypos+1),
getGrid(xpos+2,ypos),getGrid(xpos+2,ypos-1),getGrid(xpos+3,ypos+1),
getGrid(xpos+3,ypos),getGrid(xpos+3,ypos-1),getGrid(xpos+4,ypos) ];
atexit = (xpos == exitx - 1 && ypos == exity );
break;
case 3:
aspect = [  getGrid(xpos+1,ypos),getGrid(xpos-1,ypos),getGrid(xpos+1,ypos-1),
getGrid(xpos,ypos-1),getGrid(xpos-1,ypos-1),getGrid(xpos+1,ypos-2),
getGrid(xpos,ypos-2),getGrid(xpos-1,ypos-2),getGrid(xpos+1,ypos-3),
getGrid(xpos,ypos-3),getGrid(xpos-1,ypos-3),getGrid(xpos,ypos-4) ];
atexit = (xpos == exitx && ypos == exity+1 );
break;
}

// initialise the view data
view = [    "\\                         /","  \\                     /  ",
"    \\                 /    ","      \\             /      ",
"        \\         /        ","          \\     /          ",
"            \\ /            ","            / \\            ",
"          /     \\          ","        /         \\        ",
"      /             \\      ","    /                 \\    ",
"  /                     \\  ","/                         \\" ];

// paint in the visible walls
if( !aspect[0] ) 
render( 0,3, ["   ","==\\","..|","..|","..|","..|","..|","..|","..|","..|","..|","..|","==/","   " ] );
if( !aspect[1] ) 
render( 24,3,["   ","/==","|..","|..","|..","|..","|..","|..","|..","|..","|..","|..","\\==","   " ] );
if( !aspect[2] ) 
render( 2,5, ["     ","\\    ","|    ","|===\\","|...|","|...|","|...|","|...|","|...|","|...|","|===/","|    ","/    ","     " ] );
if( !aspect[4] ) 
render( 20,5,["     ","    /","    |","/===|","|...|","|...|","|...|","|...|","|...|","|...|","\\===|","    |","    \\","     " ] );
if( aspect[3] ) {
render( 2,23,[  "                       ", "=======================", ".......................",
".......................", ".......................", ".......................",
".......................", ".......................", ".......................",
".......................", ".......................", ".......................",
"=======================",
"                       " ] );
}
else {
if( !aspect[5] )
render( 6,3, ["   ","   ","   ","\\  ","|=\\","|.|","|.|","|.|","|.|","|=/","/  ","   ","   ","   " ] );
if( !aspect[7] )
render( 18,3,["   ","   ","   ","  /","/=|","|.|","|.|","|.|","|.|","\\=|","  \\","   ","   ","   " ] );
if( aspect[6] ) {
if( atexit ) {
render( 6,15,[  "               ","               ","               ",
       "===============",".             .",". *********** .",
       ". THE WAY OUT .",". *********** .",".             .",
       ".             .","===============","               ",
       "               ","               " ] );
}
else {
render( 6,15,[  "               ","               ","               ",
       "===============","...............","...............",
       "...............","...............","...............",
       "...............","===============","               ",
       "               ","               " ] );
}
}
else {
if( !aspect[8] )
render( 8,3, ["   ","   ","   ","   ","\\  ","|=\\","|.|","|.|","|=/","/  ","   ","   ","   ","   "] );
if( !aspect[10] )
render( 16,3,["   ","   ","   ","   ","  /","/=|","|.|","|.|","\\=|","  \\","   ","   ","   ","   "] );
if( aspect[9] ) {
render( 8,11,[  "           ","           ","           ","           ",
       "===========","...........","...........","...........",
       "...........","===========","           ","           ",
       "           ","           " ] );
}
else {
if( aspect[11] )
render( 10,7,[  "       ","       ","       ","       ","       ",
           "=======",".......",".......","=======","       ",
           "       ","       ","       ","       " ] );
      }
   }
}

// write data to viewport
var s = "";
var i;
for( i=0; i&lt;14; ++i ) s=s+"  "+view[i]+"  \n";
if(document.layers)
{
document.layers["viewport"].document.open();
document.layers["viewport"].document.write("&lt;pre&gt;"+s+"&lt;/pre&gt;");
document.layers["viewport"].document.close();
}
else {
viewport.innerHTML = "&lt;pre&gt;"+s+"&lt;/pre&gt;";
}

// display hint
var dist = Math.floor(Math.sqrt((xpos-exitx)*(xpos-exitx) + (ypos-exity)*(ypos-exity)));
var direction = ", exit lies "+dist+" steps to ";
if( xpos&gt;exitx) direction += "north";
if( xpos&lt;exitx) direction += "south";
if( ypos&gt;exity) direction += "west";
if( ypos&lt;exity) direction += "east";

if(document.layers) {
document.layers["readout"].document.open();
document.layers["readout"].document.write("Facing " + ["north","east","south","west"][dir] + direction);
document.layers["readout"].document.close();
}
else {
readout.innerHTML = "Facing " + ["north","east","south","west"][dir] + direction;
   }
}

// Turn around
function turn(x) {
dir += x;
if(dir&lt;0) dir=3;
if(dir&gt;3) dir=0;
draw();
}

// move forward
function move() {
// check there is no wall in front of player
if( !aspect[3] ) {
// change position
switch(dir) {
case 0: xpos--; break;
case 1: ypos++; break;
case 2: xpos++; break;
case 3: ypos--; break;
}
steps++;

// repaint
draw();

// check for completion
if( xpos == exitx && ypos == exity ) {
// finished!
alert(  "Well done! you reached the exit in "+steps+" steps,\n"+
"and you looked at the map "+cheats+" times.\n"+
"Press OK to see if you can do any better." );
start();
      }
   }
}

// show the map
function cheat() {
if( mapon ) {
// hide the map if it is already displayed
draw();
}
else {
// build the map
var x,y,s="";
for(x=xpos-10;x&lt;xpos+10;++x) {
for(y=ypos-10;y&lt;ypos+10;++y) {
if(getGrid(x,y))
s=s+"X";
else if( x==xpos && y==ypos ) {
if(document.layers)
// netscape does not support arrow characters
  s=s+"*"
else
  s=s+["&uarr;","&rarr;","&darr;","&larr;"][dir];
}
else if( x==exitx && y==exity ) {
if(document.layers)
s=s+"@";
else
s=s+"&theta;";
}
else
s=s+" ";
}
s=s+"\n";
}

// show the map
if( document.layers ) {
document.layers["viewport"].document.open();
document.layers["viewport"].document.write("&lt;pre&gt;"+s+"&lt;/pre&gt;");
document.layers["viewport"].document.close();
}
else {
viewport.innerHTML = "&lt;pre&gt;"+s+"&lt;/pre&gt;";
}
mapon=true;
cheats++;
   }
}
// go!
start();
//  End --&gt;
&lt;/script&gt;

 

&lt;!-- Script Size:  10.58 KB --&gt;</textarea><br><font FACE="helvetica,arial,geneva"></font></td></tr>

</table>
</form>
</FONT>
</CENTER>


</center>
</body></html>